home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
BBS in a Box 3
/
BBS in a box - Trilogy III.iso
/
Files
/
Prog
/
B-C
/
C++Source Code Fmtr Folder
/
Tests
/
UPrinting.cp
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
NeXTSTEP
RISC OS/Acorn
UTF-8
Wrap
Text File
|
1991-01-28
|
60.6 KB
|
2,219 lines
|
[
TEXT/MPS
]
// UPrinting.cp
// Copyright © 1986-1990 by Apple Computer, Inc. All rights reserved.
/*
Segmentation strategy:
PrintRes Resident
PrintMain Resident and used at initialization
PrintActual Used only during Actual Printing (imaging/spooling)
PrintImage Used during imaging only
PrintSpool Used only during printing of a Spool File
PrintDebug Debugging code
PrintFinder Code only ever accessed from Finder Printing
PrintInit One-time Initialization Code
PrintOpen Code accessed when opening new document
PrintNonRes General non-resident code
PrintDoCommand Code for Page Setup command
PrintTerminate One-time-only code, called only at Termination time
*/
#ifndef __ULIST__
#include <UList.h>
#endif
#ifndef __EDITIONS__
#include <Editions.h>
#endif
#ifndef __UAPPLICATION__
#include <UApplication.h>
#endif
#ifndef __UDOCUMENT__
#include <UDocument.h>
#endif
#ifndef __BALLOONS__
#include <Balloons.h>
#endif
#ifndef __UVIEW__
#include <UView.h>
#endif
#ifndef __UWINDOW__
#include <UWindow.h>
#endif
#ifndef __UFAILURE__
#include <UFailure.h>
#endif
#ifndef __UMACAPPUTILITIES__
#include <UMacAppUtilities.h>
#endif
#ifndef __UERRORMGR__
#include <UErrorMgr.h>
#endif
#ifndef __UPATCH__
#include <UPatch.h>
#endif
#ifndef __UMEMORY__
#include <UMemory.h>
#endif
#ifndef __UMACAPPGLOBALS__
#include <UMacAppGlobals.h>
#endif
#ifndef __UVIEWCOORDS__
#include <UViewCoords.h>
#endif
#ifndef __MENUS__
#include <Menus.h>
#endif
#ifndef __UMENUMGR__
#include <UMenuMgr.h>
#endif
#ifndef __TOOLUTILS__
#include <ToolUtils.h>
#endif
#ifndef __PACKAGES__
#include <Packages.h>
#endif
#ifndef __FONTS__
#include <Fonts.h>
#endif
#ifndef __ERRORS__
#include <Errors.h>
#endif
#ifndef __RESOURCES__
#include <Resources.h>
#endif
#ifndef __STDLIB__
#include <StdLib.h> // for abs()
#endif
#ifndef __UPRINTING__
#include <UPrinting.h>
#endif
//--------------------------------------------------------------------------------------------------
PenState gBreaksPenState;
Boolean gCancelAllPrinting;
VRect gStdPageMargins;
Handle gFinderHPrint;
TStdPrintHandler* gJobPrintHandler;
//--------------------------------------------------------------------------------------------------
typedef Str255* String255Ptr;
typedef String255Ptr* String255Handle;
// subclass may stuff some special values by redefining this
union TXWord
{
struct
{
char c1, c0;
} charVal;
struct
{
SignedByte b1, b0;
} byteVal;
struct
{
Boolean f15, f14, f13, f12, f11, f10, f9, f8, f7, f6, f5, f4, f3, f2, f1, f0;
} boolVal;
short iO;
};
//--------------------------------------------------------------------------------------------------
#pragma segment PrintRes
pascal void TPrintCommand::DoIt(void)
{
Boolean proceed;
fStdPrintHandler->Print(fCmdNumber, proceed);
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintSelCommand
pascal void TPrintCommand::Initialize(void) // override
{
inherited::Initialize();
fStdPrintHandler = NULL;
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintSelCommand
pascal void TPrintCommand::IPrintCommand(CmdNumber itsCmdNumber,
TStdPrintHandler* itsStdPrintHandler)
{
this->INoChangesCommand(itsCmdNumber, itsStdPrintHandler->fDocument, itsStdPrintHandler->fView);
fStdPrintHandler = itsStdPrintHandler;
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAFields
pascal void TPrintCommand::Fields(TObject* obj) // override
{
obj->DoToField("TPrintCommand", NULL, bClass);
obj->DoToField("fStdPrintHandler", &fStdPrintHandler, bObject);
inherited::Fields(obj);
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintActual
//$Push
// #if qTrace
//$D+
//#endif No tracing till we get the port straightened out since the current
//port could already be disposed (Thank you Direct connect ImageWriter!)
pascal void IdleProcForTStdPrintHandler(void)
{
GrafPtr savedPort;
if (gJobPrintHandler)
{
GetPort(savedPort);
SetPort(gWorkPort); // Nice safe port in a storm
gJobPrintHandler->DoPrintIdling(); // Forward to the current print job handler
SetPort(savedPort);
}
}
//$Pop
//--------------------------------------------------------------------------------------------------
#pragma segment PrintActual
pascal void TStdPrintHandler::DoPrintIdling(void)
{
const short myDlgMask = mDownMask + mUpMask + keyDownMask + keyUpMask + autoKeyMask;
char ch;
short keycode;
DialogPtr aDialog;
TDeviceEvent * event;
EventRecord anEventRecord;
short item;
Handle theItem;
short itemType;
Rect box;
long dontCare;
event = gApplication->GetEvent(myDlgMask, 0, NULL);
if (event)
{
// Workaround for LaserWriter driver bug: it tries to set GhostWindow
// so that its status window is invisible. Unfortunately, it doesn't
// always set it, so IsDialogEvent returns FALSE (the status window
// is frontmost). If ours isn't already in front, force it there.
if (fPrintDialog != FrontWindow())
gApplication->SelectWMgrWindow(fPrintDialog);
switch (event->fEventRecord.what)
{
case keyDown:
ch = (char)(event->fEventRecord.message & charCodeMask);
keycode = (short)((event->fEventRecord.message >> keyCodeMask) & 8);
if (((ch == '.') && event->fCmdKey) || ((ch == chEscape) && (keycode == kEscapeVirtualCode)))
{
/*### need a way to determine if multiple file printing is in process
if (gFinderPrinting)
item = cancel; // Want the 'Cancel All' button
else
item = 1; // Want the 'Cancel' button
*/
item = 1;
// Flash the appropriate button
GetDItem(fPrintDialog, item, itemType, theItem, box);
HiliteControl((ControlHandle)theItem, 10);
Delay(8, dontCare);
HiliteControl((ControlHandle)theItem, 0);
PrSetError(iPrAbort);
gCancelAllPrinting = TRUE;
}
break;
default:
anEventRecord = event->fEventRecord;
if (IsDialogEvent(anEventRecord) && DialogSelect(anEventRecord, aDialog, item) && (aDialog == fPrintDialog))
switch (item)
{
case 1:
PrSetError(iPrAbort);// Cancel
break;
case cancel: // Cancel All Printing
PrSetError(iPrAbort);
gCancelAllPrinting = TRUE;
break;
}
break;
}
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintActual
pascal void TStdPrintHandler::ChkPrintErr(OSErr& err,
Boolean& proceed,
Boolean& ranOutOfSpace)
{
if (proceed)
{
err = PrError();
if (err != noErr)
{
#if qDebug
if (gDebugPrinting)
cout << "Error from PrError is " << err << "\n";
#endif
proceed = FALSE;
if (err == -1)
ranOutOfSpace = TRUE;
}
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintRes
pascal void TStdPrintHandler::GetDriverName(Str255& driverName)
{
String255Handle driverHandle;
driverHandle = (String255Handle)GetString((short)kPrintDriverName);// Get current driver
// Be a little cautious, in case we accidentally pick up something
// which is not what we expect, or we can't find it.
if (driverHandle && ((**driverHandle).Length() < 64))
CopyStr255(**driverHandle, (Ptr) & driverName);
else
driverName = "";
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintInit
// Initialize the printing unit. Call exactly once
pascal void InitUPrinting(void)
{
TStdPrintHandler * aStdPrintHandler;
gCancelAllPrinting = FALSE;
gFinderHPrint = NULL;
gJobPrintHandler = NULL;
SetVRect(gStdPageMargins, 72, 72, -72, -72);// 1" margins std default
gBreaksPenState.pnLoc = gZeroPt;
gBreaksPenState.pnSize = Point(2, 2);
gBreaksPenState.pnMode = patCopy;
StuffHex((Ptr) & gBreaksPenState.pnPat, "CC663399CC663399");
gCouldPrint = TRUE;
gUPrintingInitialized = TRUE;
if (gPrintHandler == gNullPrintHandler)
{
// Install a StdPrintHandler in UMacApp
// global variable gPrintHandler
aStdPrintHandler = new TStdPrintHandler;
aStdPrintHandler->IStdPrintHandler(NULL, NULL, kSquareDots, kFixedSize, kFixedSize);
aStdPrintHandler->fFinderJobDialog = TRUE;
gPrintHandler = aStdPrintHandler;
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAPrintingRes
// Synonym For InitUPrinting
pascal void InitPrinting(void)
{
InitUPrinting();
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintSpool
pascal void TStdPrintHandler::PrintSpoolFile(Handle anHPrint,
OSErr& err,
Boolean& proceed)
{
TPrStatus prStatus;
Boolean b;
proceed = TRUE;
PrPicFile((THPrint)anHPrint, NULL, NULL, NULL, prStatus);
this->ChkPrintErr(err, proceed, b);
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintOpen
pascal void TStdPrintHandler::Initialize(void) // override
{
#if qDebug
if (!gUPrintingInitialized)
{
ProgramBreak("InitUPrinting must be called before creating a print handler.");
Failure(noErr, 0);
}
#endif
inherited::Initialize();
fFinderJobDialog = FALSE;
fFinderSetup = FALSE;
fFixedSizePages[hSel] = kFixedSize;
fFixedSizePages[vSel] = kFixedSize;
fHPrint = NULL;
fLastBreak = gZeroVPt;
fLastPrinterName = NULL;
fLastStrip = VPoint(MAXINT, MAXINT);
fMarginRes.h = 72;
fMarginRes.v = 72;
fMinimalMargins = FALSE;
fPageAreas.theMargins = gStdPageMargins; //!!! What about other fields?
fPageDirection = vSel; // Page 2 is below page 1, etc.
fPageStrips = gZeroVPt; //!!! Another default?
fPPrPort = NULL;
fPrintDialog = NULL;
fPrinterDev = kNeverInitialized;
fPrintExtent = gZeroVRect; //!!! Another default?
fShowBreaks = FALSE;
fSquareDots = kSquareDots;
fStartPage = 1;
fViewedRect = gZeroVRect; //!!! Another default?
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintOpen
pascal void TStdPrintHandler::IStdPrintHandler(TDocument* itsDocument,
TView* itsView,
Boolean itsSquareDots,
Boolean itsHFixedSize,
Boolean itsVFixedSize)
{
FailInfo fi;
this->IPrintHandler(itsView);
fDocument = itsDocument;
fSquareDots = itsSquareDots;
fFixedSizePages[hSel] = itsHFixedSize;
fFixedSizePages[vSel] = itsVFixedSize;
if (!fi.CatchFailure())
{
if (itsView)
{
// allocates a handle for the print-info, and sets my field fHPrint accordingly
this->SetDefaultPrintInfo();
if (itsDocument != NULL)
itsDocument->AttachPrintHandler(this);
fView->AttachPrintHandler(this);
}
fi.Success();
}
else
{
this->Free();
fi.ReSignal();
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintClose
pascal void TStdPrintHandler::Free(void) // override
{
Boolean dontDispose;
TDocument * itsDocument;
dontDispose = (fView != NULL);
if (dontDispose)
{
if (fView->fPrintHandler == this)
fView->AttachPrintHandler(gNullPrintHandler);
fView = NULL;
itsDocument = fDocument;
dontDispose = (itsDocument != NULL);
if (dontDispose)
{
if (itsDocument->fDocPrintHandler == this)
itsDocument->fDocPrintHandler = NULL;
dontDispose = itsDocument->fSharePrintInfo;
}
if (dontDispose)
dontDispose = (itsDocument->fPrintInfo == fHPrint);
fDocument = NULL;
}
if (!dontDispose)
fHPrint = DisposeIfHandle(fHPrint);
fHPrint = NULL; // Always drop my reference
fLastPrinterName = (StringHandle)DisposeIfHandle((Handle)fLastPrinterName);
this->BanishPrintDialog();
if (gJobPrintHandler == this) // let's be safe
gJobPrintHandler = NULL;
inherited::Free();
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintImage
pascal void TStdPrintHandler::AdornPage(void)
{
#if qDebug
const short botSlop = 8; // ??? Arbitrary choice
Str255 heading;
Str255 pgStr;
VRect handyRect;
Rect handyQDRect;
long itsWidth;
long rPlusL;
long itsBottom;
FontInfo theFontInfo;
Rect theTextRect;
if (gDebugPrinting) // Print extra stuff if debugging
{
NumToString(fFocusedPage, pgStr);
TextFont(applFont);
TextFace(normal);
TextSize(12);
heading = "-" + pgStr + "-"; // ??? Make easier for client to change this
// draw the heading
itsWidth = StringWidth(heading);
rPlusL = fPageAreas.thePaper.right + fPageAreas.thePaper.left;
itsBottom = fPageAreas.theInk.bottom - botSlop;
GetFontInfo(theFontInfo);
theTextRect.left = (short)(rPlusL - itsWidth) / 2;
theTextRect.top = (short)itsBottom - theFontInfo.ascent;
theTextRect.right = (short)(theTextRect.left + itsWidth);
theTextRect.bottom = (short)itsBottom + theFontInfo.descent;
MADrawString(heading, theTextRect, teFlushDefault);
// Additionally frame the printable area of the page if gDebugPrinting
handyRect = fPageAreas.theInk;
fView->ViewToQDRect(handyRect, handyQDRect);
PenSize(1, 1);
FrameRect(handyQDRect);
// Frame the 'interior' of the page
handyRect = fPageAreas.theInterior;
fView->ViewToQDRect(handyRect, handyQDRect);
PenSize(2, 2);
FrameRect(handyQDRect);
}
#endif
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintActual
pascal void TStdPrintHandler::BanishPrintDialog(void)
{
if (fPrintDialog)
{
if (fPrintDialog == qd.thePort) // Only need to invalidate focus if freed
// dialog is the current port
{
gApplication->InvalidateFocus();
SetPort(gWorkPort);
}
DisposDialog(fPrintDialog);
fPrintDialog = NULL;
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintRes
// Called from fView->DoBreakFollowing(),
pascal VCoordinate TStdPrintHandler::BreakFollowing(VHSelect vhs,
VCoordinate prevBreak,
Boolean& automatic)// override
{
VHSelect orthoVHS;
VCoordinate newLoc;
orthoVHS = gOrthogonal[vhs];
automatic = TRUE;
newLoc = Min(prevBreak + fViewPerPage[orthoVHS], fPrintExtent[botRight][orthoVHS]);
#if qDebug
if (newLoc <= prevBreak)
{
cout << form("No advance in BreakFollowing; vhs: %1d prevBreak: %1d newLoc: %1d view size: ", (short)vhs, prevBreak, newLoc, fPrintExtent[botRight][orthoVHS]);
ProgramBreak("No advance in BreakFollowing");
}
#endif
return newLoc;
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintNonRes
pascal Boolean FindLimit(VCoordinate,
Boolean,
void* staticLink)
{
++(*((long*)staticLink));
return FALSE;
}
pascal void TStdPrintHandler::CalcPageStrips(VPoint& pageStrips)// override
{
VHSelect ortho;
long nStrips;
// If pages are of fixed size, then simple divide the total size by the
// page size. Otherwise, count up the page breaks one by one.
for (VHSelect vhs = vSel; vhs <= hSel; ++vhs)
{
ortho = gOrthogonal[vhs];
if (fFixedSizePages[ortho])
pageStrips[vhs] = (fPrintExtent[botRight][ortho] - fPrintExtent[topLeft][ortho] + fViewPerPage[ortho] - 1) / fViewPerPage[ortho];
else
{
nStrips = 0;
this->EachBreak(vhs, TRUE, FindLimit, &nStrips);
pageStrips[vhs] = nStrips;
}
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintNonRes
pascal void TStdPrintHandler::CalcViewPerPage(VPoint& amtPerPage)// override
{
for (VHSelect vhs = vSel; vhs <= hSel; ++vhs)
amtPerPage[vhs] = Max(1, (fPageAreas.thePaper[botRight][vhs] - fPageAreas.thePaper[topLeft][vhs] - labs(fPageAreas.theMargins[topLeft][vhs]) - labs(fPageAreas.theMargins[botRight][vhs])));
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintRes
// this msg is sent to all views if my associated document is the kind where one
// copy of the PrintInfo is shared among all views
pascal void ItChanged(TView* aView,
void*)
{
aView->DoPrinterChanged();
}
pascal void TStdPrintHandler::CheckPrinter(void)// override
{
PageAreas oldPageAreas = fPageAreas;
long oldPrinterDev = fPrinterDev;
Point oldDevRes(fDeviceRes);
Point oldMarginRes(fMarginRes);
Boolean didChange;
Boolean msgSent;
Str255 driverName;
VRect aRect, bRect;
// It costs an open and several LoadResources to call PrValidate. Before
// doing so, check to see if the printer has actually changed.
this->GetDriverName(driverName);
if (!fLastPrinterName || (!EqualString(**fLastPrinterName, driverName, FALSE, TRUE)))
{
// Printer name has changed…
fLastPrinterName = (StringHandle)DisposeIfHandle((Handle)fLastPrinterName);// out with the old
fLastPrinterName = NewString(driverName);// in with the new
FailNIL(fLastPrinterName);
this->ValidatePrintRecord(didChange); // …and validate the print record.
}
// Store latest data from MacPrint prInfo record into my own instance variables
RectToVRect(((TPPrint) * fHPrint)->rPaper, fPageAreas.thePaper);
fMarginRes = Point(((TPPrint) * fHPrint)->prInfo.iVRes, ((TPPrint) * fHPrint)->prInfo.iHRes);// read the new device resolution values
fDeviceRes = fMarginRes;
fPrinterDev = ((TPPrint) * fHPrint)->prInfo.iDev;
RectToVRect(((TPPrint) * fHPrint)->prInfo.rPage, fPageAreas.theInk);
if (!fMinimalMargins)
fPageAreas.theMargins = VRect(IntMultiply((short)fPageAreas.theMargins.top, fMarginRes.v) / oldMarginRes.v, IntMultiply((short)fPageAreas.theMargins.left, fMarginRes.h) / oldMarginRes.h, IntMultiply((short)fPageAreas.theMargins.bottom, fMarginRes.v) / oldMarginRes.v, IntMultiply((short)fPageAreas.theMargins.right, fMarginRes.h) / oldMarginRes.h);
aRect = fPageAreas.thePaper;
bRect = fPageAreas.theInk;
if ((aRect != oldPageAreas.thePaper) || (bRect != oldPageAreas.theInk) || (fDeviceRes != oldDevRes) || (oldPrinterDev == kNeverInitialized))
{
msgSent = FALSE; // something important to our projection model changed...
if (fDocument)
if (fDocument->fSharePrintInfo)
{
fDocument->ForAllViewsDo(ItChanged, this);
msgSent = TRUE;
}
if (!msgSent) // didn't send msg to all views, current company included,
// so now we need to tell must my local view
fView->DoPrinterChanged();
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintImage
pascal void TStdPrintHandler::ChooseSpoolFile(Str255& spoolFileName,
short& spoolVRefNum,
long& pagesPerSubjob)
{
spoolFileName = ""; // Default choices tell MacPrint to use its
// standard choice algorithm
spoolVRefNum = 0;
// Print Shop suggests attempting to print entire document. If it
// runs out of space, then PerformPrinting will retry with a
// smaller number of pages.
pagesPerSubjob = MAXINT;
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintRes
pascal void TStdPrintHandler::ClosePrintShop(void)
{
#if qDebug
OSErr err;
#endif
PrClose();
#if qDebug
err = PrError(); // Now check for fresh error from MacPrint --
// only for debugging, since ChkPrintErr
// checks afresh in the real world
if (err != noErr)
cout << form("Error from MacPrint is: %1d\n", err);
#endif
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintRes
pascal void TStdPrintHandler::DoInMacPrint(pascal void(* WhatToDo)(void* staticLink),
void* staticLink)
{
FailInfo fi;
if (gCouldPrint)
{
PrSetError(noErr); // Clear printer-error flag
if (!fi.CatchFailure())
{
this->OpenPrintShop();
(*WhatToDo)(staticLink); // Do what needs to be done
fi.Success();
}
else
{
this->ClosePrintShop();
SetPort(gWorkPort); // Might be left looking at a dead port
gApplication->InvalidateFocus();
fi.ReSignal();
}
this->ClosePrintShop();
SetPort(gWorkPort); // Might be left looking at a dead port
gApplication->InvalidateFocus();
}
// NB: if gCouldPrint is FALSE, DoInMacPrint is a no-op
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintSelCommand
pascal void TStdPrintHandler::DoMenuCommand(CmdNumber aCmdNumber)// override
{
Boolean proceed;
TPrintCommand * aPrintCommand;
switch (aCmdNumber)
{
case cPrint:
this->CheckPrinter();
if (this->PoseJobDialog())
{
aPrintCommand = new TPrintCommand;
aPrintCommand->IPrintCommand(aCmdNumber, this);
this->PostCommand(aPrintCommand);
}
break;
case cPrintOne:
this->CheckPrinter();
if (this->SetupPrintOne())
{
aPrintCommand = new TPrintCommand;
aPrintCommand->IPrintCommand(aCmdNumber, this);
this->PostCommand(aPrintCommand);
}
break;
case cPageSetup:
this->PosePageSetupDialog(proceed, TRUE);
break;
case cShowBreaks: // Toggle state of "Show Breaks"
fShowBreaks =!fShowBreaks;
this->InvalPageFeedback(); // force redraw of area the breaks did or will occupy
break;
default:
inherited::DoMenuCommand(aCmdNumber);
break;
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintRes
pascal void TStdPrintHandler::DoSetupMenus(void)// override
{
inherited::DoSetupMenus();
if (gCouldPrint && fView &&!MemSpaceIsLow())
{
Enable(cPrint, TRUE);
Enable(cPageSetup, TRUE);
Enable(cPrintOne, TRUE);
}
EnableCheck(cShowBreaks, TRUE, fShowBreaks);
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintRes
// A local class to help iterate over the list of handles and insert into a DescList
class CPageBreaks
{
VHSelect& fOrthoVHS;
VHSelect& fVHS;
short& fWhichBreak;
const VRect& fViewArea;
TView* fView;
public:
CPageBreaks(VHSelect& theOrthoVHS,
VHSelect& theVHS,
short& whichBreak,
const VRect& theViewArea,
TView* theView) :
fOrthoVHS(theOrthoVHS),
fVHS(theVHS),
fWhichBreak(whichBreak),
fViewArea(theViewArea),
fView(theView)
{
}
pascal Boolean DrawABreak(VCoordinate loc,
Boolean automatic);
};
#pragma segment PrintRes
pascal Boolean CPageBreaks::DrawABreak(VCoordinate loc,
Boolean automatic)
{
if (loc > fViewArea[botRight][fOrthoVHS])
return TRUE;
else
{
++fWhichBreak;
if (loc > (fViewArea[topLeft][fOrthoVHS] - Point(gBreaksPenState.pnSize)[fOrthoVHS]))
fView->DoDrawPageBreak(fVHS, fWhichBreak, loc, automatic);
return FALSE;
}
}
#pragma segment PrintRes
// Draws page breaks and page numbers
pascal void TStdPrintHandler::DrawPrintFeedback(const VRect& area)// override
{
if (qDebug)
fView->AssumeFocused();
if (fShowBreaks || gDebugPrinting)
{
VHSelect vhs;
VHSelect orthoVHS;
short whichBreak = 0;
CPageBreaks aPageBreak(orthoVHS, vhs, whichBreak, area, fView);
this->SetPrintExtent(); // Make sure print extent is accurate before starting
#if qDebug
if (gDebugPrinting) // Now draw Page numbers in the corners of pages, if desired
{
TextStyle pageNumStyle;
SetTextStyle(pageNumStyle, applFont, bold, 9, gRGBBlack);
SetPortTextStyle(pageNumStyle);
}
#endif
SetPenState(gBreaksPenState);
for (vhs = vSel; vhs <= hSel; ++vhs)
{
orthoVHS = gOrthogonal[vhs];
whichBreak = 0;
this->EachBreak(vhs, FALSE, (DoToBreakType) & CPageBreaks::DrawABreak, &aPageBreak);
}
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintRes
#if qDebug
pascal void TStdPrintHandler::DrawPageBreak(VHSelect vhs,
long whichBreak,
VCoordinate loc,
Boolean)// override
#else
pascal void TStdPrintHandler::DrawPageBreak(VHSelect vhs,
long/* whichBreak */,
VCoordinate loc,
Boolean)// multiple declarations to eliminate compiler warnings
#endif
{
VPoint vPt;
Point qdStartPt;
Point qdEndPt;
vPt[gOrthogonal[vhs]] = loc;
vPt[vhs] = 0;
qdStartPt = fView->ViewToQDPt(vPt);
vPt[vhs] = fView->fSize[vhs] - Point(gBreaksPenState.pnSize)[vhs];
qdEndPt = fView->ViewToQDPt(vPt);
if (fShowBreaks)
{
MoveTo(qdStartPt.h, qdStartPt.v);
LineTo(qdEndPt.h, qdEndPt.v);
}
#if qDebug
if (gDebugPrinting)
if (vhs == hSel)
{
VCoordinate hLoc;
Str255 aString;
FontInfo theFontInfo;
Rect theTextRect;
for (long i = 0; i <= fPageStrips.v; ++i)
{
if (i == 0)
hLoc = 0;
else
this->GetBreakCoord(vSel, i, hLoc);
GetFontInfo(theFontInfo);
NumToString(this->StripToPage(whichBreak - 1, i), aString);
// top computed based on the bottom - text height
theTextRect = Rect(qdStartPt.v - 3 - theFontInfo.ascent, (short)hLoc + 3, qdStartPt.v - 3 + theFontInfo.descent, (short)hLoc + 3 + StringWidth(aString));
MADrawString(aString, theTextRect, teFlushDefault);
NumToString(this->StripToPage(whichBreak, i), aString);
// top computed based on the bottom - text height
theTextRect = Rect(qdEndPt.v + 10 - theFontInfo.ascent, (short)hLoc + 3, qdEndPt.v + 10 + theFontInfo.descent, (short)hLoc + 3 + StringWidth(aString));
MADrawString(aString, theTextRect, teFlushDefault);
NumToString(this->StripToPage(whichBreak - 1, i - 1), aString);
// top computed based on the bottom - text height
theTextRect = Rect(qdStartPt.v - 3 - theFontInfo.ascent, (short)hLoc - StringWidth(aString) - 3, qdStartPt.v - 3 + theFontInfo.descent, (short)hLoc - 3);
MADrawString(aString, theTextRect, teFlushDefault);
NumToString(this->StripToPage(whichBreak, i - 1), aString);
// top computed based on the bottom - text height
theTextRect = Rect(qdEndPt.v + 10 - theFontInfo.ascent, (short)hLoc - StringWidth(aString) - 3, qdEndPt.v + 10 + theFontInfo.descent, (short)hLoc - 3);
MADrawString(aString, theTextRect, teFlushDefault);
}
}
#endif
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintImage
pascal void TStdPrintHandler::DrawPageInterior(void)
{
fView->DrawContents(); // i.e., by default, the same code used for drawing on the screen
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintRes
pascal void TStdPrintHandler::EachBreak(VHSelect vhs,
Boolean includeLast,
pascal Boolean(* DoToBreak)(VCoordinate loc,
Boolean automatic,
void* staticLink),
void* staticLink)
{
VCoordinate startLoc;
VCoordinate endLoc;
VCoordinate loc;
Boolean automatic;
Boolean done;
VCoordinate prevBreak = 0;
startLoc = fPrintExtent[topLeft][gOrthogonal[vhs]];
endLoc = fPrintExtent[botRight][gOrthogonal[vhs]];
loc = startLoc;
automatic = TRUE;
done = FALSE;
while ((loc < endLoc) &&!done)
{
if (loc != startLoc)
done = (*DoToBreak)(loc, automatic, staticLink);
if (qDebug)
prevBreak = loc;
loc = fView->DoBreakFollowing(vhs, loc, automatic);
if (qDebug && (loc <= prevBreak))
ProgramBreak("thisBreak (loc) <= prevBreak");// Thanks much to Larry T. !
}
if (includeLast)
(*DoToBreak)(loc, automatic, staticLink);
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintFields
pascal void TStdPrintHandler::Fields(TObject* obj)
{
obj->DoToField("TStdPrintHandler", NULL, bClass);
obj->DoToField("fPageAreas", NULL, bTitle);
obj->DoToField(" thePaper", &fPageAreas.thePaper, bRect);
obj->DoToField(" theInk", &fPageAreas.theInk, bRect);
obj->DoToField(" theMargins", &fPageAreas.theMargins, bRect);
obj->DoToField(" theInterior", &fPageAreas.theInterior, bRect);
obj->DoToField("fPrintExtent", &fPrintExtent, bVRect);
obj->DoToField("fFixedSizePages[h]", &fFixedSizePages[hSel], bBoolean);
obj->DoToField("fFixedSizePages[v]", &fFixedSizePages[vSel], bBoolean);
obj->DoToField("fHPrint", &fHPrint, bHandle);
obj->DoToField("fPageStrips", &fPageStrips, bPoint);
obj->DoToField("fStartPage", &fStartPage, bLongInt);
obj->DoToField("fPrinterDev", &fPrinterDev, bLongInt);
obj->DoToField("fLastPrinterName", &fLastPrinterName, bStringHandle);
obj->DoToField("fPageDirection", &fPageDirection, bVHSelect);
obj->DoToField("fShowBreaks", &fShowBreaks, bBoolean);
obj->DoToField("fFinderSetup", &fFinderSetup, bBoolean);
obj->DoToField("fFinderJobDialog", &fFinderJobDialog, bBoolean);
obj->DoToField("fSquareDots", &fSquareDots, bBoolean);
obj->DoToField("fMinimalMargins", &fMinimalMargins, bBoolean);
obj->DoToField("fLastStrip", &fLastStrip, bPoint);
obj->DoToField("fLastBreak", &fLastBreak, bVPoint);
obj->DoToField("fViewedRect", &fViewedRect, bVRect);
obj->DoToField("fMarginRes", &fMarginRes, bPoint);
obj->DoToField("fPrintDialog", &fPrintDialog, bWindowPtr);// need a bDialogPtr
obj->DoToField("fPPrPort", NULL, bTitle);
if (fPPrPort)
{
obj->DoToField(" gPort", &fPPrPort, bGrafPtr);
obj->DoToField(" gProcs", &fPPrPort->gProcs, bQDProcs);
obj->DoToField(" IGParam1", &fPPrPort->lGParam1, bLongInt);
obj->DoToField(" IGParam2", &fPPrPort->lGParam2, bLongInt);
obj->DoToField(" IGParam3", &fPPrPort->lGParam3, bLongInt);
obj->DoToField(" IGParam4", &fPPrPort->lGParam4, bLongInt);
obj->DoToField(" fOurPtr", &fPPrPort->fOurPtr, bBoolean);
obj->DoToField(" fOurBits", &fPPrPort->fOurBits, bBoolean);
}
inherited::Fields(obj);
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintImage
pascal void TStdPrintHandler::FocusOnBorder(void)
{
VRect rectToClipTo(fPageAreas.theInk);
Rect qdRectToClipTo;
// Only works for newer LaserWriter drivers
SetOrigin((short)fPageAreas.theInk.left, (short)fPageAreas.theInk.top);
fView->ViewToQDRect(rectToClipTo, qdRectToClipTo);
ClipRect(qdRectToClipTo);
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintImage
pascal void TStdPrintHandler::FocusOnInterior(void)// override
{
VRect rectToClip;
VRect aRect;
VPoint theOrigin;
VPoint theVOrigin;
VRect aVRect;
Rect qdRectToClip;
aRect = fPageAreas.theInk;
theOrigin = fPageAreas.theInk[topLeft];
for (VHSelect vhs = vSel; vhs <= hSel; ++vhs)
if (fView->fSize[vhs] > kMaxCoord)
theVOrigin[vhs] = gPageOffset[vhs];
else
{
theVOrigin[vhs] = 0;
theOrigin[vhs] = theOrigin[vhs] + gPageOffset[vhs];
aRect[topLeft][vhs] = aRect[topLeft][vhs] + gPageOffset[vhs];
aRect[botRight][vhs] = aRect[botRight][vhs] + gPageOffset[vhs];
}
SetOrigin((short)theOrigin.h, (short)theOrigin.v);
fView->fViewToQDOffset = theVOrigin;
// Clip the page to the intersection of the visible part of the view and the
// printable area of the page. Note that in some cases (e.g., a WYSIWYG
// word processor which showed the complete page margin) parts of
// the interior might lie outside theInk. We must clip to theInk to
// avoid slowing down PostScript printers.
rectToClip = fViewedRect;
SectVRect(rectToClip, aRect, rectToClip);
fView->ViewToQDRect(rectToClip, qdRectToClip);
ClipRect(qdRectToClip);
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintRes
pascal void TStdPrintHandler::GetBreakCoord(VHSelect vhs,
long whichBreak,
VCoordinate& loc)
{
Boolean automatic;
long startBreak;
VHSelect orthoVHS;
VCoordinate prevBreak = 0;
orthoVHS = gOrthogonal[vhs];
if (fFixedSizePages[orthoVHS])
loc = fPrintExtent[topLeft][orthoVHS] + fViewPerPage[orthoVHS] * whichBreak;
else if (whichBreak == fLastStrip[vhs])
loc = fLastBreak[vhs];
else
{
if (whichBreak > fLastStrip[vhs])
{
startBreak = fLastStrip[vhs] + 1;
loc = fLastBreak[vhs];
}
else
{
startBreak = 1;
loc = fPrintExtent[topLeft][gOrthogonal[vhs]];
}
for (long i = startBreak; i <= whichBreak; ++i)
{
if (qDebug)
prevBreak = loc;
loc = fView->DoBreakFollowing(vhs, loc, automatic);// ??? error handling???
if (qDebug && (loc <= prevBreak))
ProgramBreak("thisBreak (loc) <= prevBreak");
}
}
loc = Min(loc, fPrintExtent[botRight][orthoVHS]);
fLastStrip[vhs] = whichBreak;
fLastBreak[vhs] = loc;
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintActual
pascal void TStdPrintHandler::GetDocName(Str255& docName)
{
TView * aView;
if (fDocument)
fDocument->GetTitle(docName);
if (docName.IsEmpty())
{
aView = fView->GetRootView();
if (aView && aView->IsMemberClass(GetClassIDFromName("TWindow")))
((TWindow *)aView)->GetTitle(docName);
}
#if qDebug
if (docName.IsEmpty())
ProgramBreak("GetDocName can''t get a document or window name");
#endif
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintMain
pascal Handle TStdPrintHandler::GetPrintInfo(void)
{
return fHPrint;
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintNonRes
pascal void TStdPrintHandler::InstallMargins(const VRect& newMargins,
Boolean areMinimalMargins)
{
fMinimalMargins = areMinimalMargins;
if (fMinimalMargins)
{
fPageAreas.theMargins = fPageAreas.theInk;
fPageAreas.thePaper[topLeft] -= fPageAreas.theMargins[topLeft];
fPageAreas.thePaper[botRight] -= fPageAreas.theMargins[botRight];
fPageAreas.theInterior = fPageAreas.theInk;
}
else
{
fPageAreas.theMargins = newMargins;
fPageAreas.theInterior = fPageAreas.thePaper;
fPageAreas.theMargins[topLeft] += fPageAreas.theInterior[topLeft];
fPageAreas.theMargins[botRight] += fPageAreas.theInterior[botRight];
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintNonRes
pascal void TStdPrintHandler::InvalPageFeedback(void)
{
if (this->ShowsOnScreen())
fView->ForceRedraw();
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintNonRes
pascal void TStdPrintHandler::LocatePageInterior(long,
VPoint& loc)// override
{
loc = fPageAreas.thePaper[topLeft];
fPageAreas.theMargins[topLeft] += loc;
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintActual
pascal long TStdPrintHandler::MaxPageNumber(void)// override
{
return fStartPage + (fPageStrips.v * fPageStrips.h) - 1;
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintActual
pascal void TStdPrintHandler::OneSubJob(long subjobFirstPage,
long subjobLastPage,
Boolean justSpool,
Boolean,
Boolean& ranOutOfSpace,
long& lastPageTried,
Boolean& proceed)
{
long noOfCopies;
OSErr err;
TPrJob & printJob = ((TPPrint) * fHPrint)->prJob;
FailInfo fi;
#if qDebug
if (gDebugPrinting)
cout << form("OneSubJob entered for pages %1d through %1d, proceed=", subjobFirstPage, subjobLastPage) << proceed << "\n";
#endif
ranOutOfSpace = FALSE;
lastPageTried = subjobFirstPage - 1;
printJob.iFstPage = 1;
printJob.iLstPage = (short)(subjobLastPage - subjobFirstPage + 1);
if (printJob.bJDocLoop == bSpoolLoop)
noOfCopies = 1;
else
noOfCopies = printJob.iCopies;
fPPrPort = PrOpenDoc((THPrint)fHPrint, NULL, NULL);
// ??? need to allow/encourage app to supply nonNil args?
this->ChkPrintErr(err, proceed, ranOutOfSpace);
gCurrPrintHandler = this;
if (proceed)
{
fView->InvalidateFocus();
fView->UpdateCoordinates();
gPrinting = TRUE;
SetPort((GrafPtr)fPPrPort);
fView->BeInPort((GrafPtr)fPPrPort);
gPrinting = TRUE;
if (!fView->Focus())
{
#if qDebug
ProgramBreak("Can''t focus view while printing");
#endif
}
for (long pass = 1; pass <= noOfCopies; ++pass)
for (long aPageNumber = subjobFirstPage; aPageNumber <= subjobLastPage; ++aPageNumber)
if (proceed)
{
lastPageTried = aPageNumber;
if (!fi.CatchFailure())
{
this->PrintPage(aPageNumber);
fi.Success();
}
else
{
proceed = FALSE;
err = fi.error; // pass along client's error code Why???
}
this->ChkPrintErr(err, proceed, ranOutOfSpace);
}
gPrinting = FALSE;
fView->InvalidateFocus();
fView->UpdateCoordinates();
fView->BeInPort(fView->GetGrafPort());
}
gCurrPrintHandler = NULL;
PrCloseDoc(fPPrPort); // This will close the port!
SetPort(gWorkPort);
this->ChkPrintErr(err, proceed, ranOutOfSpace);
if (ranOutOfSpace)
return;
else if (proceed)
{
if (printJob.bJDocLoop == bSpoolLoop)
if (!justSpool)
this->PrintSpoolFile(fHPrint, err, proceed);
}
if (!proceed)
if (err != iPrAbort)
Failure(err, 0);
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintRes
pascal void TStdPrintHandler::OpenPrintShop(void)
{
OSErr err;
PrOpen(); // Open the print shop
err = PrError(); // Get code
if (err != noErr)
{
if ((err == fnfErr) || (err == resFNotFound))
err = errNoPrintDrvr;
Failure(err, 0);
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintRes
pascal VPoint TStdPrintHandler::PageToStrip(long pageNumber)
{
long normalizedPageNum;
VHSelect ortho;
VPoint strip;
normalizedPageNum = pageNumber - fStartPage + 1;
ortho = gOrthogonal[fPageDirection];
strip[ortho] = (normalizedPageNum - 1) / fPageStrips[ortho];
strip[fPageDirection] = normalizedPageNum - ((strip[ortho]) * fPageStrips[ortho]) - 1;
return strip;
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintRes
// !!! Need to test this!
pascal VPoint TStdPrintHandler::PointToPageStrip(const VPoint& pointInView)
{
long loc;
Boolean automatic;
VPoint pageStrip;
VCoordinate prevBreak = 0;
for (VHSelect vhs = vSel; vhs <= hSel; ++vhs)
if (fFixedSizePages[vhs])
pageStrip[vhs] = (pointInView[vhs] / fViewPerPage[vhs]) + 1;
else
{
pageStrip[vhs] = 1;
loc = fPrintExtent[topLeft][vhs]; // ??? or orthogonal?
while (pointInView[vhs] > loc)
// ??? or orthogonal?
{
if (qDebug)
prevBreak = loc;
loc = fView->DoBreakFollowing(vhs, loc, automatic);
if (qDebug && (loc <= prevBreak))
ProgramBreak("thisBreak (loc) <= prevBreak");
pageStrip[vhs]++; // ??? Check the pascal. This may be wrong. !!!
}
}
return pageStrip;
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintActual
class CPrintDialogs
{
Boolean& fResult;
Handle& fHPrint;
public:
CPrintDialogs(Boolean& proceed,
Handle& printHandle) :
fResult(proceed),
fHPrint(printHandle)
{
}
pascal void CallJobDialog(void);
pascal void CallStyleDialog(void);
pascal void CallPrValidate(void);
};
#pragma segment PrintActual
pascal void CPrintDialogs::CallJobDialog(void)
{
SetCursor(qd.arrow);
if (gApplication)
gApplication->InvalidateMouseRegions();
fResult = PrJobDialog((THPrint)fHPrint);
}
#pragma segment PrintActual
pascal void CPrintDialogs::CallStyleDialog(void)
{
SetCursor(qd.arrow);
if (gApplication != NULL)
gApplication->InvalidateMouseRegions();
fResult = PrStlDialog((THPrint)fHPrint);
}
#pragma segment PrintActual
pascal void CPrintDialogs::CallPrValidate(void)
{
fResult = PrValidate((THPrint)fHPrint);
}
#pragma segment PrintActual
pascal Boolean TStdPrintHandler::PoseJobDialog(void)
{
Boolean b;
Boolean proceed;
OSErr err;
TPrJob & printJob = ((TPPrint) * fHPrint)->prJob;
CPrintDialogs aJobDialog(proceed, fHPrint);
proceed = TRUE;
// PrepareForDialog;
this->DoInMacPrint((WhatToDoType) & CPrintDialogs::CallJobDialog, &aJobDialog);
this->ChkPrintErr(err, proceed, b);
// Rectify the range as a public service if needed
if (printJob.iFstPage > printJob.iLstPage)
{
short temp;
temp = printJob.iLstPage;
printJob.iLstPage = printJob.iFstPage;
printJob.iFstPage = temp;
}
gApplication->UpdateAllWindows();
return proceed;
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintActual
// Needs to be here because it may be called from Print
pascal void TStdPrintHandler::PosePageSetupDialog(Boolean& proceed,
Boolean isUndoable)
{
Boolean react;
TPrintStyleChangeCommand * aPrintStyleChangeCommand;
CPrintDialogs aPageSetupDialog(react, fHPrint);
react = FALSE; // in case MacPrint code not accessible
if (!isUndoable)
{
// PrepareForDialog;
this->DoInMacPrint((WhatToDoType) & CPrintDialogs::CallStyleDialog, &aPageSetupDialog);
if (react)
this->CheckPrinter();
}
else
{
// Must setup command before putting up page setup dialog because the
// command records the current print record to make it undoable.
aPrintStyleChangeCommand = new TPrintStyleChangeCommand;
aPrintStyleChangeCommand->IPrintStyleChangeCommand(this);
// Put up the Page Setup Dialog
this->DoInMacPrint((WhatToDoType) & CPrintDialogs::CallStyleDialog, &aPageSetupDialog);
if (react) // User specified a change
{
BlockMove((Ptr) * fHPrint, (Ptr) * (aPrintStyleChangeCommand->fNewHPrint), sizeof(TPrint));
this->PostCommand(aPrintStyleChangeCommand);
}
else // User did not specify a change
aPrintStyleChangeCommand = (TPrintStyleChangeCommand *)FreeIfObject(aPrintStyleChangeCommand);
}
proceed = react;
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintActual
pascal void TStdPrintHandler::PosePrintDialog(void)
{
short dlgNumber;
DialogTHndl dlogTemplate;
Str255 docName;
short itemNo;
Handle theItem;
short itemType;
Rect box;
Str255 itemText;
short preDocName,
constTitle;
/*### need to determine if multiple file printing is in process
if (gFinderPrinting)
{
dlgNumber = phFinderPrintDialog;
itemNo = 3;
}
else
{
dlgNumber = phSpoolPrintDialog;
itemNo = 2;
}
*/
dlgNumber = phSpoolPrintDialog;
itemNo = 2;
// Can't use GetNewCenteredDialog because vertically centering the dialog may cause it
// to interfere with the Print Manager's status windows. Therefore, leave the vertical
// location of the dialog fixed.
SetCursor(qd.arrow);
gApplication->InvalidateMouseRegions();
dlogTemplate = (DialogTHndl)GetResource('DLOG', dlgNumber);
if (dlogTemplate)
{
CenterRectOnScreen((*dlogTemplate)->boundsRect, TRUE, FALSE, FALSE);
fPrintDialog = GetNewDialog(dlgNumber, (Ptr)NULL, (WindowPtr) - 1);
FailNIL(fPrintDialog);
}
else
{
#if qDebug
cout << "You may have forgotten to include Printing.rsrc in your .r file…\n";
ProgramBreak("The print job dialog resource can''t be found.");
#endif
FailNILResource((Handle)dlogTemplate);
}
// Substitute the document name for '<<!=>>' in 'Document “<<!=>>” is being printed'.
// ParamText would be a lot simpler, but the Print Mgr. also uses ParamText, and
// the substitution doesn't happen until draw time.
this->GetDocName(docName);
GetDItem(fPrintDialog, itemNo, itemType, theItem, box);
if (theItem)
{
GetIText(theItem, itemText);
if (ParseTitleTemplate(itemText, preDocName, constTitle) && SubstituteInTitle(itemText, docName, preDocName, constTitle))
SetIText(theItem, itemText);
}
((TPPrint) * fHPrint)->prJob.pIdleProc = &IdleProcForTStdPrintHandler;
SetWTitle(fPrintDialog, docName); // In case Print Mgr. needs it.
DrawDialog(fPrintDialog);
}
//--------------------------------------------------------------------------------------------------
// ???Was in PrintActual. Doesn't really belong in this segment,
//but can get unloaded during Finder printing otherwise.
#pragma segment PrintRes
pascal void TStdPrintHandler::Print(CmdNumber itsCmdNumber,
Boolean& proceed)// override
{
FailInfo fi;
gCancelAllPrinting = FALSE;
this->SetPrintExtent(); // Make sure we've got the right area.
if (!fi.CatchFailure())
{
if (gCouldPrint)
{
long firstPage;
long lastPage;
OSErr err;
Str255 spoolFileName;
short spoolVRefNum;
TPrJob aPrJob = ((TPPrint) * fHPrint)->prJob;
long totalPages;
long lastPrinted;
long lastAttempted;
long pagesPerSubjob;
long firstSubjobPage;
Boolean proceed = TRUE;
Boolean ranOutOfSpace = FALSE;
Boolean spoolMethod;
Boolean justSpool = (itsCmdNumber == cPrintToFile);
VPoint pageStrips;
FailInfo fi;
PrSetError(noErr); // Clear printer-error flag
this->OpenPrintShop();
gJobPrintHandler = this; // be visible to the idleProc
fView->DoCalcPageStrips(pageStrips);
fPageStrips = pageStrips;
firstPage = Max(aPrJob.iFstPage, fStartPage);
lastPage = Min(aPrJob.iLstPage, this->MaxPageNumber());
if (lastPage < firstPage)
err = Alert(phNoPages, NULL);
else
{
totalPages = lastPage - firstPage + 1;
spoolMethod = (aPrJob.bJDocLoop == bSpoolLoop);
if (spoolMethod)
{
this->ChooseSpoolFile(spoolFileName, spoolVRefNum, pagesPerSubjob);
// if justSpool is true, then the spool filename and vRefNum will already
// have been stuffed into the prJob record before this method is called
if (!justSpool)
{
if (!spoolFileName.IsEmpty())
{
aPrJob.pFileName = &spoolFileName;
aPrJob.iFileVol = spoolVRefNum;
}
}
}
else
pagesPerSubjob = MAXINT;
lastPrinted = firstPage - 1;
pagesPerSubjob = Min(pagesPerSubjob, totalPages);
this->PosePrintDialog();
if (!fi.CatchFailure())
{
do
{
firstSubjobPage = lastPrinted + 1;
this->OneSubJob(firstSubjobPage, firstSubjobPage + pagesPerSubjob - 1, justSpool, (pagesPerSubjob < totalPages), ranOutOfSpace, lastAttempted, proceed);
if (proceed)
lastPrinted = lastAttempted;
if (ranOutOfSpace)
{
pagesPerSubjob = lastAttempted - 1 - firstSubjobPage;
proceed = TRUE;
}
} while ((lastPrinted == lastPage) || (pagesPerSubjob < 1) ||!proceed);
if (pagesPerSubjob < 1)
Failure(errSpooling, 0);
fi.Success();
}
else
{
this->BanishPrintDialog();
fi.ReSignal();
}
this->BanishPrintDialog(); // having removed, put back here, unsure if exactly right
} // if there are pages within requested range
gJobPrintHandler = NULL; // out damned spot
}
this->ClosePrintShop();
SetPort(gWorkPort); // Might be left looking at a dead port
gApplication->InvalidateFocus();
fi.Success();
}
else
{
this->ClosePrintShop();
SetPort(gWorkPort); // Might be left looking at a dead port
gApplication->InvalidateFocus();
// Certain Print Manager errors should not result in any alert,
// since the Print Manager will have already put one up.
if ((fi.error >= -8160) && (fi.error <= -8150))
Failure(0, msgPrintFailed);
if (fi.message == 0)
this->GetDocName(gErrorParm3);
FailNewMessage(fi.error, fi.message, msgPrintFailed);
fi.ReSignal();
}
proceed =!gCancelAllPrinting;
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintNonRes
pascal void TStdPrintHandler::PrinterChanged(void)// override
{
fView->DoPagination();
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintImage
pascal void TStdPrintHandler::PrintPage(long aPageNumber)// Print a single page
{
FailInfo fi;
this->SetPage(aPageNumber); // gets gPage set up correctly for coordinate transformations
if (!fi.CatchFailure())
{
#if qDebug
GrafPtr aPort;
#endif
PrOpenPage(fPPrPort, NULL);
FailOSErr(PrError());
this->FocusOnInterior();
this->DrawPageInterior();
#if qDebug
GetPort(aPort);
if (aPort != ((GrafPtr) fPPrPort))
ProgramBreak("The view''s DrawPageInterior method changed the grafPort");
#endif
FailOSErr(PrError());
this->FocusOnBorder();
this->AdornPage();
FailOSErr(PrError());
fi.Success();
}
else
{
PrClosePage(fPPrPort);
fi.ReSignal();
}
PrClosePage(fPPrPort);
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintNonRes
// Called from fView.DoPagination.
pascal void TStdPrintHandler::RedoPageBreaks(void)// override
{
Boolean worryAboutBreaks;
VPoint oldViewPerPage, viewPerPage;
VPoint pageStrips;
VRect newInterior, oldInterior;
worryAboutBreaks = (fView->GetGrafPort()) && gInitialized && (fShowBreaks || gDebugPrinting);
if (worryAboutBreaks)
this->InvalPageFeedback(); // invalidate old page breaks, if relevant
this->SetPrintExtent();
oldInterior = fPageAreas.theInterior;
oldViewPerPage = fViewPerPage;
this->SetMargins();
// computes view per page from papersize, printer resolution, margins desired, view resolution,
//and, if desired, other factors such as printable rectangle of page and font metrics in the
//printer space
fView->DoCalcViewPerPage(viewPerPage);
fViewPerPage = viewPerPage;
this->SetPageInterior(kUsualPages);
newInterior = fPageAreas.theInterior;
#if qDebug
if (gDebugPrinting)
if (oldInterior != newInterior)
ProgramBreak("Setting new interior");
#endif
if (oldInterior != newInterior)
fView->PageInteriorChanged(newInterior);
#if qDebug
if (gDebugPrinting)
if (oldViewPerPage != viewPerPage)
ProgramBreak("Setting new view per page");
#endif
if ((oldInterior != newInterior) || (oldViewPerPage != viewPerPage))
fView->AdjustSize();
fView->DoCalcPageStrips(pageStrips);
fPageStrips = pageStrips;
if (worryAboutBreaks)
this->InvalPageFeedback(); // force redraw of new page breaks, if relevant
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintNonRes
pascal void CallPrintDefault(void* staticLink)
{
PrintDefault(*((THPrint *)staticLink));
}
pascal void TStdPrintHandler::Reset(void)
{
THPrint anHPrint = (THPrint)fHPrint;
Boolean didChange;
Boolean inited = FALSE;
FailInfo fi;
if (anHPrint)
{
if (gCouldPrint)
{
if (!fi.CatchFailure())
{
TXWord printerFlags;
this->DoInMacPrint(CallPrintDefault, &anHPrint);
if (fSquareDots)
{
printerFlags.iO = ((TPPrint) * fHPrint)->prStl.wDev;
if (printerFlags.byteVal.b1 == 1)// 1 == bDevCItoh => ImageWriter
{
// Set the square-pixel flag in the print record, then
// ensure we didn't corrupt it.
printerFlags.boolVal.f2 = TRUE;
this->ValidatePrintRecord(didChange);
}
}
inited = TRUE;
fi.Success();
}
}
// MacPrint code unavailable, but we want some plausible things
// anyway - set up for Portrait Tall Adj.
// ??? Replace the following expensive stuffing code with StuffHex
// calls or a GetResource or some such, later
if (!(gCouldPrint && inited))
{
(*anHPrint)->iPrVersion = 0; // something invalid
(*anHPrint)->prInfo.iHRes = 72;
(*anHPrint)->prInfo.iVRes = 72;
(*anHPrint)->prInfo.rPage = Rect(0, 0, 752, 576);// must have its top left & (0,0)
(*anHPrint)->rPaper = Rect(-36, -18, 756, 594);
(*anHPrint)->prStl.iPageV = 1320;// 11 inches in 120th of an inch
(*anHPrint)->prStl.iPageH = 1020;// 8.5 inches in 120th of an inch
}
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintNonRes
pascal void TStdPrintHandler::SetPrintExtent(void)
{
VRect printExtent;
fView->GetPrintExtent(printExtent);
// Make sure the bottom or right is not smaller than the top or left.
// This can happen when views are being created and before the window
// has been resized to its actual size.
printExtent.bottom = Max(printExtent.bottom, printExtent.top);
printExtent.right = Max(printExtent.right, printExtent.left);
fPrintExtent = printExtent;
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintOpen
pascal void TStdPrintHandler::SetDefaultPrintInfo(void)
{
Boolean didChange;
Boolean wantValidate = FALSE;
Boolean haveHPrint = FALSE;
fHPrint = DisposeIfHandle(fHPrint);
if (fView)
{
if (fDocument && (fDocument->fSharePrintInfo && fDocument->fPrintInfo))
{
fHPrint = fDocument->fPrintInfo;
haveHPrint = TRUE;
}
}
if (haveHPrint)
wantValidate = TRUE;
else
{
fHPrint = NewPermHandle(sizeof(TPrint));
this->Reset();
}
if (wantValidate)
this->ValidatePrintRecord(didChange);
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintNonRes
pascal void TStdPrintHandler::SetMargins(void)
{
VRect someMargins;
someMargins = fPageAreas.theMargins;
this->InstallMargins(someMargins, fMinimalMargins);
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintImage
pascal void TStdPrintHandler::SetPage(long aPageNumber)
{
VRect viewedRect;
VPoint strip;
fFocusedPage = aPageNumber;
strip = this->PageToStrip(aPageNumber);
for (VHSelect vhs = vSel; vhs <= hSel; ++vhs)
{
this->GetBreakCoord(gOrthogonal[vhs], strip[vhs], viewedRect[topLeft][vhs]);
this->GetBreakCoord(gOrthogonal[vhs], strip[vhs] + 1, viewedRect[botRight][vhs]);
}
this->SetPageInterior(aPageNumber);
fView->DoSetPageOffset(viewedRect[topLeft]);
fViewedRect = viewedRect;
#if qDebug
if (gDebugPrinting)
cout << form("pg #: %1d;", aPageNumber) << " coord == " << viewedRect[topLeft] << " Page Interior: " << fPageAreas.theInterior << "\n";
#endif
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintNonRes
pascal void TStdPrintHandler::SetPageInterior(long pageNumber)// override
{
VPoint pegPoint;
for (VHSelect vhs = vSel; vhs <= hSel; ++vhs)
{
fPageAreas.theInterior[topLeft][vhs] = fPageAreas.thePaper[topLeft][vhs] + fPageAreas.theMargins[topLeft][vhs];
fPageAreas.theInterior[botRight][vhs] = fPageAreas.theInterior[topLeft][vhs] + fViewPerPage[vhs];
}
this->LocatePageInterior(pageNumber, pegPoint);
fPageAreas.theInterior[topLeft] = pegPoint;
for (vhs = vSel; vhs <= hSel; ++vhs)
fPageAreas.theInterior[botRight][vhs] = fPageAreas.theInterior[topLeft][vhs] + fViewPerPage[vhs];
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintImage
pascal void TStdPrintHandler::SetPageOffset(const VPoint& coord)// override
{
for (VHSelect vhs = vSel; vhs <= hSel; ++vhs)
gPageOffset[vhs] = coord[vhs] - fPageAreas.theInterior[topLeft][vhs];
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintFinder
pascal Boolean TStdPrintHandler::SetupForFinder(void)// override
{
Boolean proceed;
Boolean didChange;
proceed = TRUE;
this->CheckPrinter(); // Uncertain if necessary???
if (fFinderSetup)
this->PosePageSetupDialog(proceed, FALSE);
if (proceed)
{
this->ShowDocBeingPrinted(TRUE);
if (fFinderJobDialog ||!gFinderHPrint)
{
proceed = this->PoseJobDialog();
// Merge into gPrintHandler, in case next document needs it
if (!gFinderHPrint)
gFinderHPrint = NewPermHandle(sizeof(TPrint));
BlockMove((*fHPrint), (*gFinderHPrint), sizeof(TPrint));
}
else
{
PrJobMerge((THPrint)gFinderHPrint, (THPrint)fHPrint);
this->ValidatePrintRecord(didChange);
}
this->ShowDocBeingPrinted(FALSE);
}
return proceed;
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintRes
pascal Boolean TStdPrintHandler::SetupPrintOne(void)
{
Boolean didChange;
// Call PrValidate to 1) make sure the record is OK, and
// 2) Get the LaserWriter driver to get the name of the front window.
this->ValidatePrintRecord(didChange);
PrSetError(noErr);
((TPPrint) * fHPrint)->prJob.iFstPage = 0;
((TPPrint) * fHPrint)->prJob.iLstPage = 9999;// This is what the Print Mgr. uses
return TRUE; // Should always be able to continue from here
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintFinder
pascal void TStdPrintHandler::ShowDocBeingPrinted(Boolean entering)
{
Str255 aTitle;
if (entering)
{
fPrintDialog = GetNewDialog(phWhichDoc, (Ptr)NULL, (WindowPtr) - 1);
if (fPrintDialog)
{
this->GetDocName(aTitle);
SetWTitle(fPrintDialog, aTitle);
DrawDialog(fPrintDialog);
}
#if qDebug
else
ProgramBreak(ConcatNumber("Unable to load dialog ", phWhichDoc));
#endif
}
else
this->BanishPrintDialog();
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintRes
pascal Boolean TStdPrintHandler::ShowsOnScreen(void)
{
if (fView)
return fView->IsVisible();
else
return FALSE;
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintRes
pascal long TStdPrintHandler::StripToPage(long hStrip,
long vStrip)
{
Point strip((short)vStrip, (short)hStrip);
VHSelect ortho;
ortho = gOrthogonal[fPageDirection];
return strip[fPageDirection] * fPageStrips[ortho] + strip[ortho] + fStartPage;
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintRes
pascal void TStdPrintHandler::ValidatePrintRecord(Boolean& didChange)
{
FailInfo fi;
CPrintDialogs aPrValidateDialog(didChange, fHPrint);
if (!fi.CatchFailure())
{
this->DoInMacPrint((WhatToDoType) & CPrintDialogs::CallPrValidate, &aPrValidateDialog);
fi.Success();
}
else
this->Reset();
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintDoCommand
pascal void TPrintStyleChangeCommand::Initialize(void)// override
{
inherited::Initialize();
fNewHPrint = NULL;
fOldHPrint = NULL;
fStdPrintHandler = NULL;
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintDoCommand
pascal void TPrintStyleChangeCommand::IPrintStyleChangeCommand(TStdPrintHandler* itsPrintHandler)
{
TDocument * changedDocument;
FailInfo fi;
changedDocument = itsPrintHandler->fDocument;
this->ICommand(cChangePrinterStyle, changedDocument, itsPrintHandler->fView);
fStdPrintHandler = itsPrintHandler;
fCausesChange = (changedDocument && (changedDocument->fSavePrintInfo));
if (!fi.CatchFailure())
{
fOldHPrint = NewPermHandle(sizeof(TPrint));
// Make a copy of the old version of the PrintInfo record
BlockMove(*(itsPrintHandler->fHPrint), *fOldHPrint, sizeof(TPrint));
fNewHPrint = NewPermHandle(sizeof(TPrint));
fi.Success();
}
else
{
this->Free();
fi.ReSignal();
}
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintDoCommand
pascal void TPrintStyleChangeCommand::Free(void)// override
{
fOldHPrint = DisposeIfHandle(fOldHPrint);
fNewHPrint = DisposeIfHandle(fNewHPrint);
inherited::Free();
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintDoCommand
pascal void TPrintStyleChangeCommand::DoIt(void)// override
{
fStdPrintHandler->CheckPrinter(); // Will find it changed, and hence dispatch
// to view's DoPrinterChanged
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintFields
pascal void TPrintStyleChangeCommand::Fields(TObject* obj)
{
obj->DoToField("TPrintStyleChangeCommand", NULL, bClass);
obj->DoToField("fStdPrintHandler", &fStdPrintHandler, bObject);
obj->DoToField("fOldHPrint", &fOldHPrint, bHandle);
obj->DoToField("fNewHPrint", &fNewHPrint, bHandle);
inherited::Fields(obj);
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintDoCommand
pascal void TPrintStyleChangeCommand::UndoIt(void)// override
{
BlockMove(*fOldHPrint, *(fStdPrintHandler->fHPrint), sizeof(TPrint));
fStdPrintHandler->CheckPrinter(); // Will find it changed, and hence dispatch
// to view's DoPrinterChanged
}
//--------------------------------------------------------------------------------------------------
#pragma segment PrintDoCommand
pascal void TPrintStyleChangeCommand::RedoIt(void)// override
{
BlockMove(*fNewHPrint, *(fStdPrintHandler->fHPrint), sizeof(TPrint));
fStdPrintHandler->CheckPrinter(); // Will find it changed, and hence dispatch
// to view's DoPrinterChanged
}